package edu.luc.concordia;

import java.io.*;
import java.util.*;

import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

import org.w3c.dom.*;

/**
 * Copyright 2008 Project Concordia
 * <p>
 * This file is part of RetailReturnSystem.
 * <p>
 * RetailReturnSystem is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <p>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
 * <hr>
 * Calculates the final pieces, generate the receipt, and updates the receipt file.
 * @author Paul Zolnierczyk
 * @version 0.2 2008-11-20
 */

public class ReceiptGenerator {

	private ArrayList<Product> myScannedItems = new ArrayList<Product>();
	private ArrayList<Product> myCalculatedPrices = new ArrayList<Product>();
	private ArrayList<String> myFinalReceipt = new ArrayList<String>();

	private Inventory inventory;


	/**
	 * Constructor class
	 * @param items - is the list of scanned items generated by PurchaseRecorder class.
	 */
	public ReceiptGenerator(ArrayList<Product> items){
		myScannedItems = items;
		inventory = new Inventory();

	}

	/**
	 * Calculate the final prices with Subtotal, 
	 * GST (Goods and Services Tax) and Total
	 */
	private void calculateFinalPrices()
	{

		double subTotal = 0.0;
				
		//printing the lines with items
		for (int i = 0; i < myScannedItems.size(); i++)
		{

			Product tempProduct = myScannedItems.get(i);
			String description = tempProduct.getDescription();
			String uid = tempProduct.getUID();
			ArrayList<PriceScheme> priceScheme = tempProduct.getPriceScheme();
			double price = priceScheme.get(0).getPrice();
			myFinalReceipt.add(uid + " " + description + " " + price);

			subTotal += price;
		}
		double tax = 0.0;
		
		//to display the footer of the receipt 
		tax = subTotal * 0.07f;
		myFinalReceipt.add("SubTotal = $" + String.format("%.2f", subTotal));
		myFinalReceipt.add("GST = $" + String.format("%.2f",tax));
		myFinalReceipt.add("Total: $" + String.format("%.2f",(subTotal + tax)));
	}
	
	private void calculateFinalPricesC2()
	{

		Date date = new Date();
		// TODO: Initialize myCategoryItems
//		ArrayList<Product>  myCategoryItems = new ArrayList<Product>();
//		ArrayList<PriceScheme> priceSchemes = myCategoryItems.get(0).getPriceScheme();
		Product nextCategory = null;
		PriceScheme scheme1 = null;
		ArrayList<Product>  myCategoryItems = null;

		/* Cycle 2 */
		
		// while myScannedItems > 0
		while(myScannedItems.size() > 0)
		{
			// remove first item and place in temp arraylist
			myCategoryItems = new ArrayList<Product>();
			nextCategory = myScannedItems.remove(0);
			myCategoryItems.add(nextCategory);			
			
			for(PriceScheme temp : nextCategory.getPriceScheme())
			{
				if(temp.getType().equals("category"))
				{
					scheme1 = temp;
					break;
				}
			}
			
			// for loop
			for(int i = 0; i < myScannedItems.size(); ++i)
			{
				if(nextCategory.getCategoryID().equals(myScannedItems.get(i).getCategoryID()))
				{
					// remove all items in same category and put in temp arraylist
					myCategoryItems.add(myScannedItems.get(i));
					myScannedItems.remove(i);
					i--;
				}
				// now we have an arraylist of products from all the same category
			}			

			// send whole arraylist to pricescheme.calculateCategoryPrice(arraylist)
			myCategoryItems = scheme1.calculateCategoryPrice(myCategoryItems);		
			
			// if member
			// also calculate member price scheme and give better price to customer
			//TODO Check if customer is member
			if(false)
			{
				ArrayList<Product> myBetterPrice = new ArrayList<Product>();
				ArrayList<Product> myMemberCategoryItems = (ArrayList<Product>) myCategoryItems.clone();
				ArrayList<PriceScheme> priceSchemes = null;
				PriceScheme scheme2 = priceSchemes.get(1);
				
				myMemberCategoryItems = scheme2.calculateCategoryPrice(myMemberCategoryItems);				
				
				for(int i = 0; i <= myCategoryItems.size(); ++i)
				{
					if(myMemberCategoryItems.get(i).getCalculatedPrice() >= myCategoryItems.get(i).getCalculatedPrice())
					{
						myBetterPrice.add(myCategoryItems.get(i));
					}
					else
					{
						myBetterPrice.add(myMemberCategoryItems.get(i));
					}
				}
				myCalculatedPrices.addAll(myBetterPrice);
			}		
			else
			{
				// add to some final arraylist (myCalculatedPrices)
				myCalculatedPrices.addAll(myCategoryItems);	
			}
			// method will return arraylist with all prices set			
		}
		
		//calculate total sale of myCalculatedPrices and send to system price scheme
		double subTotal = 0.0;
    	for(Product product : myCalculatedPrices)
    	{
    		subTotal += product.getCalculatedPrice();
    	}
    	
    	for(PriceScheme temp : nextCategory.getPriceScheme())
		{
			if(temp.getType().equals("system") && !temp.isMember())
			{
				scheme1 = temp;
				break;
			}
		}
		
		subTotal = scheme1.calculateSystemPrice(subTotal);		
		
		// loop through purchased items
		double total = 0.0;
		double tax = inventory.getTaxRate();
		
		for(int i = 0; i < myCalculatedPrices.size(); ++i)
		{
			// if item is taxable
			if(myCalculatedPrices.get(i).isTaxable())
			{
				// apply tax
				total += (myCalculatedPrices.get(i).getCalculatedPrice() * (1 + tax));
			}
			else
			{
				total += myCalculatedPrices.get(i).getCalculatedPrice();
			}
		}
		
		// setup myFinalReceipt
		
		//just to preserve some cycle 1 functionality
		myScannedItems = myCalculatedPrices;
		
		//printing the lines with items
		for (int i = 0; i < myCalculatedPrices.size(); ++i)
		{
			Product tempProduct = myCalculatedPrices.get(i);
			String description = tempProduct.getDescription();
			String uid = tempProduct.getUID();
			double price = tempProduct.getCalculatedPrice();
			
			myFinalReceipt.add(uid + " " + description + " " + price);
		}
		
		//to display the footer of the receipt 
		myFinalReceipt.add("SubTotal = $" + String.format("%.2f", subTotal));
		myFinalReceipt.add("GST = $" + String.format("%.2f",tax));
		myFinalReceipt.add("Total: $" + String.format("%.2f",(total)));
		myFinalReceipt.add("Transaction Date: " + date);
		
		// if member
		// add member information
		// TODO Check if customer is member
		if(false)
		{
			//where does memberID come from
			myFinalReceipt.add("MemberID: " + "memberId");
		}
	}


	/**
	 * To open the file "output" and add data into it.
	 */

	private void updateReceiptFile()
	{	
		FileWriter writer = null;
		double subTotal = 0.0;
		double tax = 0.0;
		double total = 0.0;
		
		//Creating an empty XML Document
			DocumentBuilderFactory dbfac =  DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = null;
			try 
			{
				docBuilder = dbfac.newDocumentBuilder();
			}
			catch (ParserConfigurationException e) 
			{
				e.printStackTrace();
			}
			Document doc = docBuilder.newDocument();

			//Creating the XML tree

			//create the root element and add it to the document
			Element root = doc.createElement("finalReceipt");
			doc.appendChild(root);
			
			try 
			{
				 writer = new FileWriter("eceipt.xml", true);
			}
			catch (IOException e1) 
			{
				e1.printStackTrace();
			}

			for (int i = 0; i < myScannedItems.size(); i++)
			{
				Product tempProduct = myScannedItems.get(i);

				//UID
				String uid = tempProduct.getUID();
				//create child element and add to root
				Element child1 = doc.createElement("uid");
				root.appendChild(child1);
				//to get uid and add uid text element to the child
				Text text1 = doc.createTextNode(uid);
				child1.appendChild(text1);

				//Description
				String description = tempProduct.getDescription();
				//create child element and add to root
				Element child2 = doc.createElement("description");
				root.appendChild(child2);
				//to get description and add description text element to the child
				Text text2 = doc.createTextNode(description);
				child2.appendChild(text2);
				
				//SubTotal
				double price = tempProduct.getCalculatedPrice();
				subTotal += price;
				String totalPriceString = Double.toString(subTotal);
				//create child element and add to root
				Element child4 = doc.createElement("subTotal");
				root.appendChild(child4);
				//to get subTotal and add subTotal text element to the child
				Text text4 = doc.createTextNode(totalPriceString);
				child4.appendChild(text4);

				//GST
				if(tempProduct.isTaxable())
				{
					tax = subTotal * 0.07f;
				}
				else
				{
					tax = 0;
				}				
				String taxString = Double.toString(tax);
				//create child element and add to root
				Element child5 = doc.createElement("gstTax");
				root.appendChild(child5);
				//to get tax and add tax text element to the child
				Text text5 = doc.createTextNode(taxString);
				child5.appendChild(text5);
				
				//Total
				total = subTotal + tax;
				String totalString = Double.toString(total);
				//create child element and add to root
				Element child6 = doc.createElement("total");
				root.appendChild(child6);
				//to get tax and add tax text element to the child
				Text text6 = doc.createTextNode(totalString);
				child6.appendChild(text6);

				//Output the XML
				//set up a transformer
				TransformerFactory transfac = TransformerFactory.newInstance();
				Transformer trans = null;
				try 
				{
					trans = transfac.newTransformer();
					
				}
				catch (TransformerConfigurationException e) 
				{
					e.printStackTrace();
				}
				trans.setOutputProperty(OutputKeys.INDENT, "yes");

				//create string from xml tree
				StringWriter sw = new StringWriter();
				StreamResult result = new StreamResult(sw);
				DOMSource source = new DOMSource(doc);
				try 
				{
					trans.transform(source, result);
					
				}
				catch (TransformerException e) 
				{
					e.printStackTrace();
				}
				String xmlString = sw.toString();
				
				//to display xml in myReceipt.xml and close it
				try 
				{		
					writer.write(xmlString);
					writer.flush();				
				} 
				catch (IOException e) 
				{
					e.printStackTrace();
				}
			}
			
			try
			{
				writer.close();
			}
			catch (IOException e) 
			{
				e.printStackTrace();
			}
	}

	

	/**
	 * Generates the final receipt.
	 * @return generateFinalReceipt - an ArrayList of myFinalReceipt called by the 
	 * CalculateFinalPrices() and UpdateReceiptFile() methods
	 */
	public ArrayList<String> generateFinalReceipt(){
		//calculateFinalPrices();
		calculateFinalPricesC2();
		updateReceiptFile();
		return myFinalReceipt;

	}

}
